Skip to content

fix(playground): fix React error #310 — hooks after early returns#429

Merged
ajitpratap0 merged 1 commit intomainfrom
feat/phase1-marketing-website
Mar 22, 2026
Merged

fix(playground): fix React error #310 — hooks after early returns#429
ajitpratap0 merged 1 commit intomainfrom
feat/phase1-marketing-website

Conversation

@ajitpratap0
Copy link
Owner

Production Blocker Fix

Symptom: gosqlx.dev/playground shows "Failed to load SQL parser" with Minified React error #310

Root Cause: useState(copied) and useCallback(handleCopy) were declared on lines 193–201, after two conditional early returns (if (loading) at line 112, if (error) at line 176). This violates the React Rules of Hooks.

Why it broke today: Before commit #423 (commit gosqlx.wasm to fix 404), the WASM binary returned HTTP 404. The component always ended up in the error branch, so both renders exited with the same hook count (9 hooks) — the violation was hidden. After #423, the WASM loads successfully and the component transitions loading=true → ready=true. React sees 9 hooks on render 1 and 11 hooks on render 2 → error #310 ("Rendered more hooks than during the previous render").

Fix: Move useState(false) and useCallback(handleCopy) above all conditional returns (line 112). No other logic changed.

Test plan

  • Visit https://gosqlx.dev/playground after deploy — should load and parse SQL
  • No React error in console
  • Copy button works (tests the moved hooks)

🤖 Generated with Claude Code

@vercel
Copy link

vercel bot commented Mar 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gosqlx-website Ready Ready Preview, Comment Mar 23, 2026 2:30pm

… React error #310

useState(copied) and useCallback(handleCopy) were declared after the
if (loading) and if (error) early returns, violating the Rules of Hooks.

When the WASM binary was a 404, the component always hit the error branch
so both renders exited with the same hook count. After committing the WASM
binary (#423), the component now successfully transitions loading→ready,
causing React to see 11 hooks instead of 9 on the second render → #310.

Fix: move both hooks above all conditional returns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ajitpratap0 ajitpratap0 force-pushed the feat/phase1-marketing-website branch from 22229e8 to 744ed99 Compare March 22, 2026 13:31
@github-actions
Copy link

github-actions bot commented Mar 22, 2026

Claude finished @ajitpratap0's task —— View job


Reviewing PR: Fix React Hooks Violation ✅

Review Checklist:

  • Read the modified Playground.tsx file
  • Analyze the React hooks positioning and implementation
  • Check for proper React patterns and best practices
  • Evaluate if the fix addresses the root cause properly
  • Look for any other potential issues or improvements
  • Provide comprehensive review feedback

APPROVED - Excellent Fix!

This is a textbook solution to a classic React hooks violation. The fix is minimal, precise, and addresses the exact root cause.

🎯 Root Cause Analysis - Spot On

The PR description perfectly identifies the issue:

  • Before: useState(copied) and useCallback(handleCopy) were declared on lines 112-119, after early returns on lines 121 and 185
  • After: Both hooks moved to lines 112-119, before any conditional returns
  • Why it worked before: WASM 404 meant component always hit the error branch (9 hooks), hiding the violation
  • Why it broke: After WASM fix, component transitions from loading→ready, causing hook count mismatch (9→11)

📊 Code Quality Assessment

✅ Strengths:

  • Perfect hook placement: Lines 112-119 are the ideal location - after all other hooks but before any early returns
  • Minimal change scope: Only moved the problematic hooks, no unnecessary refactoring
  • Preserved logic: handleCopy and copied state work identically
  • Clean implementation: No performance regressions or side effects

✅ React Best Practices:

  • Follows Rules of Hooks perfectly
  • Proper dependency arrays in useCallback (empty [] is correct here)
  • Consistent hook ordering maintained
  • No conditional hook calls

🔍 Security & Performance

Security: ✅ No concerns

  • navigator.clipboard.writeText() with hardcoded safe string
  • No user input involved in the copy operation

Performance: ✅ Optimized

  • useCallback prevents unnecessary re-renders of dependent components
  • useState(false) is lightweight
  • No performance impact from the repositioning

🧪 Test Coverage Recommendations

The current fix is solid, but consider these test additions:

// Test hook stability across loading states
it('should maintain consistent hook order during loading transitions', () => {
  // Mock WASM loading sequence: loading → ready
  // Verify no React hook violations occur
});

// Test copy functionality (the moved hooks)
it('should copy install command and show feedback', async () => {
  // Verify handleCopy works correctly after the move
});

🚀 Deployment Readiness

This fix is production-ready:

  • ✅ Addresses the exact production blocker
  • ✅ No breaking changes
  • ✅ Follows React best practices
  • ✅ Minimal risk/impact

📝 Minor Suggestions (Optional)

  1. Code organization: The hook placement is now perfect - no changes needed
  2. Type safety: Current implementation is properly typed
  3. Documentation: PR description is excellent and explains the issue thoroughly

Final Verdict: This is an exemplary bug fix that demonstrates strong React knowledge and debugging skills. The fix is surgical, well-reasoned, and production-ready. 🚀

@ajitpratap0 ajitpratap0 merged commit cec5acc into main Mar 22, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant